<template>
  <canvas ref="canvas"></canvas>
</template>

<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount } from "vue";

// 创建canvas和context的引用
const canvas = ref<HTMLCanvasElement | null>(null);
const ctx = ref<CanvasRenderingContext2D | null>(null);
const particles = ref<Particle[]>([]);
let text = ref<string | null>(null);

// 初始化canvas的尺寸
function initCanvasSize() {
  if (canvas.value) {
    canvas.value.width = window.innerWidth * devicePixelRatio;
    canvas.value.height = window.innerHeight * devicePixelRatio;
  }
}

// 获取随机数
function getRandom(min: number, max: number): number {
  return Math.floor(Math.random() * (max + 1 - min) + min);
}

// 创建粒子类
class Particle {
  x: number;
  y: number;
  size: number;

  constructor() {
    const r = Math.min(canvas.value?.width || 0, canvas.value?.height || 0) / 2;
    const cx = (canvas.value?.width || 0) / 2;
    const cy = (canvas.value?.height || 0) / 2;
    const rad = (getRandom(0, 360) * Math.PI) / 180;
    this.x = cx + r * Math.cos(rad);
    this.y = cy + r * Math.sin(rad);
    this.size = getRandom(2 * devicePixelRatio, 7 * devicePixelRatio);
  }

  // 绘制粒子
  draw() {
    if (ctx.value) {
      ctx.value.beginPath();
      ctx.value.fillStyle = "#5445544d";
      ctx.value.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
      ctx.value.fill();
    }
  }

  // 移动粒子
  moveTo(tx: number, ty: number) {
    const duration = 500; // 500ms的运动时间
    const sx = this.x;
    const sy = this.y;
    const xSpeed = (tx - sx) / duration;
    const ySpeed = (ty - sy) / duration;
    const startTime = Date.now();
    const _move = () => {
      const t = Date.now() - startTime;
      const x = sx + xSpeed * t;
      const y = sy + ySpeed * t;
      this.x = x;
      this.y = y;
      if (t >= duration) {
        this.x = tx;
        this.y = ty;
        return;
      }
      // x，y改动一点
      requestAnimationFrame(_move);
    };
    _move();
  }
}

// 清空canvas
function clear() {
  if (ctx.value) {
    ctx.value.clearRect(
      0,
      0,
      canvas.value?.width || 0,
      canvas.value?.height || 0
    );
  }
}
let animationFrameId: number;
// 绘制canvas
function draw() {
  clear();
  update();
  particles.value.forEach((p) => p.draw());
  animationFrameId = requestAnimationFrame(draw);
}

// 获取当前时间
function getText(): string {
  return new Date().toTimeString().substring(0, 8);
}

// 更新canvas
function update() {
  if (!ctx.value) return;
  const newText = getText();
  if (newText === text.value) {
    return;
  }
  clear();
  text.value = newText;
  // 画文本
  const { width, height } = canvas.value || { width: 0, height: 0 };
  ctx.value.fillStyle = "#000";
  ctx.value.textBaseline = "middle";
  ctx.value.font = `${140 * devicePixelRatio}px 'DS-Digital', sans-serif`;
  ctx.value.fillText(
    text.value,
    (width - ctx.value.measureText(text.value).width) / 2,
    height / 2
  );
  const points = getPoints();
  clear();
  for (let i = 0; i < points.length; i++) {
    let p = particles.value[i];
    if (!p) {
      p = new Particle();
      particles.value.push(p);
    }
    const [x, y] = points[i];
    p.moveTo(x, y);
  }
  if (points.length < particles.value.length) {
    particles.value.splice(points.length);
  }
}

// 获取canvas上的点
function getPoints(): [number, number][] {
  if (!ctx.value) return [];
  const { width, height } = canvas.value || { width: 0, height: 0 };
  const imageData = ctx.value.getImageData(0, 0, width, height);
  const data = imageData.data;
  const points: [number, number][] = [];
  const gap = 6;
  for (let i = 0; i < width; i += gap) {
    for (let j = 0; j < height; j += gap) {
      const index = (i + j * width) * 4;
      const r = data[index];
      const g = data[index + 1];
      const b = data[index + 2];
      const a = data[index + 3];
      if (r === 0 && g === 0 && b === 0 && a === 255) {
        points.push([i, j]);
      }
    }
  }
  return points;
}

// 在组件挂载时初始化canvas和context，并开始绘制
onMounted(() => {
  if (canvas.value) {
    ctx.value = canvas.value.getContext("2d", { willReadFrequently: true });
    initCanvasSize();
    draw();
  }
});
onBeforeUnmount(() => {
  // 清除动画
  cancelAnimationFrame(animationFrameId);
});
</script>

<style scoped>
canvas {
  width: 100%;
  height: 100%;
}
</style>
